package com.zzq.my.jetpacks.jectpackapp.dsl

import android.text.Editable
import android.text.TextWatcher
import android.widget.TextView

/**
 * 描述：这个实现类由三个部分组成：
1. 原接口方法对应的 Kotlin 函数对象，函数对象的签名与对应的方法签名保持一致。
2. DSL 函数，函数名称、签名都与原接口的方法一一对应，用于接收 lambda 赋值给 Kotlin 函数对象。
3. 原接口方法的实现，每个接口方法的实现，都是对实现类中 Kotlin 函数对象的调用。
 * 作者：zhuangzeqin
 * 时间: 2022/4/2-13:45
 * 邮箱：zzq@eeepay.cn
 * 备注:
 */
class TextWatcherDslImpl:TextWatcher {
    /**
     * 3 原接口方法的实现，每个接口方法的实现，都是对实现类中 Kotlin 函数对象的调用。
     */
    override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        beforeTextChanged?.invoke(s,start,count,after)
    }

    override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        onTextChanged?.invoke(s,start,before,count)
    }

    override fun afterTextChanged(s: Editable?) {
        afterTextChanged?.invoke(s)
    }
    //==========================================================================
    //1 原接口对应的kotlin函数对象
    private var afterTextChanged: ((Editable?) -> Unit)? = null

    private var beforeTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null

    private var onTextChanged: ((CharSequence?, Int, Int, Int) -> Unit)? = null


    /**
     * 2 DSL中使用的函数，一般保持同名即可
     */
    fun afterTextChangedDsl(method: (Editable?) -> Unit) {
        afterTextChanged = method
    }

    fun beforeTextChangedDsl(method: (CharSequence?, Int, Int, Int) -> Unit) {
        beforeTextChanged = method
    }

    fun onTextChangedDsl(method: (CharSequence?, Int, Int, Int) -> Unit) {
        onTextChanged = method
    }
    
}

/**
 * 创建与原函数同名的扩展函数，函数参数为实现类扩展函数
 * 扩展函数与原函数同名可以方便使用者调用，无需记忆其他函数名，
 * 如果担心混淆，可以在函数名后加上 Dsl 用以区分。
 * 该函数的参数是我们第一步创建的实现类的扩展函数，这是为了实现 DSL 语法。
 */
fun TextView.addTextChangedListenerDsl(block: TextWatcherDslImpl.()->Unit){
    val listener  = TextWatcherDslImpl().also(block)
    this.addTextChangedListener(listener)
}

//todo 使用的时候如下使用这种方式时，可以说相当之优雅，我们只需要调用我们需要实现的接口方法即可，不需要使用的接口方法默认空实现。
//etString.addTextChangedListenerDsl {
//    afterTextChangedDsl {
//        if (it.toString().length >= 4) {
//            KeyboardUtils.toggleSoftInput()
//        }
//    }
//}

/**
 * 高阶函数方式比 DSL 方式更简单一点：
 * 我们创建一个同名扩展函数，使用 Closure 尾缀作为区分，该函数的参数为与接口方法一一对应的
 * Kotlin 函数对象，并给其默认值赋值为 {} 即空实现，
 * 在函数体里通过 object 关键字构建匿名内部类实现对象，在其接口方法实现中调用与之一一对应的 Kotlin 函数对象。
 *
 * inline 与 crossinline 两个关键字，这是 Koltin 特有的。inline 关键字通常用于修饰高阶函数，用于提升性能。
 * crossinline 声明的 lambda 不允许局部返回，用于避免调用者错误的使用 return 导致函数中断。
 */
inline fun TextView.addTextChangedListenerClosure(
    crossinline afterTextChanged: (Editable?) -> Unit = {},
    crossinline beforeTextChanged: (CharSequence?, Int, Int, Int) -> Unit = { charSequence, start, count, after -> },
    crossinline onTextChanged: (CharSequence?, Int, Int, Int) -> Unit = { charSequence, start, after, count -> }
) {
    val listener = object : TextWatcher {
        override fun afterTextChanged(s: Editable?) {
            afterTextChanged.invoke(s)
        }

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            beforeTextChanged.invoke(s, start, count, after)
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            onTextChanged.invoke(s, start, before, count)
        }
    }
    this.addTextChangedListener(listener)
}